/**
 * @author QL
 * @date 2021-12-24 11:47:38
 * @version V..
 * @description 声明定义全局用到的一些工具性性质的逻辑处理方法的类
 */
import router from '@/router'

class UtilMethods {
	constructor() {
		/**
		 * @author QL
		 * @param { String } debug 
		 * @date 2021-12-29 10:43:36
		 * @description 从.env环境配置文件中提取是否显示console.log的控制变量值
		 */
		this.debug = process.env.VUE_APP_DEBUG;

		/**
		 * @author QL
		 * @param { Object } antiShakeTimers 
		 * @date 2021-12-29 10:25:08
		 * @description 函数防抖方法的计时器缓存对象
		 */
		this.antiShakeTimers = {};
	}

	/**
	 * @author QL
	 * @functionName setConsole
	 * @param { Object } msg 提示性文本，开发者主观定义
	 * @param { Object } log 日志主体内容，一般是变量值
	 * @date 2021-12-24 11:56:18
	 * @version V..
	 * @description 
	 */
	setConsole(msg, log) {
		if (this.debug) {
			console.log(msg, log);
		}
	}


	/**
	 * @author QL
	 * @functionName rout
	 * @param { String } type
	 * @example
	 *   type: [
	 *     "to",
	 *     "replace",
	 *     "back"
	 *   ]
	 * @param { String } path 路径
	 * @param { Object } query 路由带的参数对象
	 * @date 2021-12-24 11:58:08
	 * @version V..
	 * @description 路由控制方法
	 */
	rout(type, path, query) {
		switch (type) {
			case 'to':
				router.push({
					path: path,
					query: query
				})
				break;
			case 'replace':
				router.replace({
					path: path,
					query: query
				})
				break;
			case 'back':
				router.back()
				break;
			default:
				break;
		}
	}

	/**
	 * @author QL
	 * @functionName splicingQuery
	 * @param { String } path 路径
	 * @param { Object } query 路径所带的参数对象
	 * @date 2021-12-24 13:46:05
	 * @version V..
	 * @description 处理路由query参数的拼接
	 */
	splicingQuery(path, query) {
		this.setConsole("参数对象：", query);
		let url = path;
		let queryKeys = Object.keys(query);
		if (typeof url == 'number') {
			this.setConsole("navigateBack参数：dalta=", path);
			return url;
		} else if (url.indexOf('?') == -1 && queryKeys.length) {
			url = path + '?';
		}
		let queryString = '';
		queryKeys.forEach((key, index) => {
			if (index > 0) {
				queryString = queryString + '&' + key + '=' + query[key];
			} else {
				queryString = queryString + key + '=' + query[key];
			}
		})
		this.setConsole("拼接处理后的路由和参数：", url + paramString);
		return url + queryString;
	}

	/**
	 * @author QL
	 * @functionName insertParams
	 * @param { String } path 基础路由
	 * @param { Object } params 路由中掺杂的参数路径
	 * @date 2021-12-24 13:47:08
	 * @version V..
	 * @description 处理路由动态路径params参数的插入
	 */
	insertPathParams(path, params) {
		let paramKeys = Object.keys(params);
		paramKeys.forEach(key => {
			if (!this.isEmpty(params[key]).isEmpty) {
				path = path + `/${params[key]}`
			}
		})
		return path;
	}

	/**
	 * @author QL
	 * @functionName isEmpty
	 * @param { * } executee 被判断的数据值
	 * @date 2021-12-24 13:48:00
	 * @version V..
	 * @description 精确判断输入变量类型，并分类判断是否为空值
	 */
	isEmpty(executee) {
		let variableType = Object.prototype.toString.call(executee);
		this.setConsole("变量数值：", executee);
		this.setConsole("变量类型：", variableType);

		let message = {
			type: variableType,
			msg: '',
			isEmpty: false,
		}

		if ([NaN, undefined, null].indexOf(executee) != -1) {
			message.msg = "变量未定义(undefined)或赋予特殊定义空值(NaN/null)！";
			message.isEmpty = true;
			return message;
		}
		let filter = ""
		switch (variableType) {
			case "[object String]":
				filter = executee.replace(/\s|&nbsp;/g, "");
				this.setConsole("string 类型变量正则过滤：", filter);
				message.msg = "string 类型变量，有效字符长度：" + filter.length;
				message.isEmpty = (filter ?? '') === '' ? true : false;
				return message;

			case "[object Number]":
				if (isNaN(executee)) {
					message.msg = "NaN 值变量";
					message.isEmpty = true;
				} else {
					message.msg = "number 类型变量，值为：" + executee;
					message.isEmpty = false;
				}
				return message;

			case "[object Boolean]":
				message.msg = "Boolean 类型变量，值为：" + executee;
				message.isEmpty = false;
				return message;

			case "[object Object]":
				message.msg =
					"Object 类型值变量，属性列表为：" + Object.keys(executee);
				message.isEmpty = Object.keys(executee).length == 0 ? true : false;
				return message;

			case "[object Array]":
				message.msg = "array 类型值变量，列表长度：" + executee.length;
				message.isEmpty = executee.length == 0 ? true : false;
				return message;
		}
	}

	/**
	 * @author QL
	 * @functionName injectionObject
	 * @param { Object }  sourceData 	源数据的对象
	 * @param { Object }  adapterDic 	目标输出对象元素属性 与 源数据对象属性 key的字典对象
	 * @param { String }  emptyHolder 	待注入值的对应目标属性为空时，待注入值使用emptyHolder填入占位值 
	 * @date 2021-12-24 13:48:32
	 * @version V..
	 * @description 对象属性适配器
	 */
	injectionObject(sourceData, adapterDic, emptyHolder) {
		this.setConsole("适配器字典：", adapterDic);
		this.setConsole("源数据对象：", sourceData);
		let retData = {};

		let adapterKeyList = [];
		let sourceKeyList = [];
		adapterKeyList = Object.keys(adapterDic);
		this.setConsole("适配器字典的key列表：", adapterKeyList);
		sourceKeyList = Object.keys(sourceData);
		this.setConsole("源数据对象的key列表：", sourceKeyList);

		adapterKeyList.forEach((adKey) => {
			if (typeof adapterDic[adKey] == 'string') {
				if (sourceKeyList.indexOf(adapterDic[adKey]) != -1 && !this.isEmpty(sourceData[
					adapterDic[adKey]]).isEmpty) {
					retData[adKey] = sourceData[adapterDic[adKey]];
				} else {
					retData[adKey] = emptyHolder.length ? emptyHolder : adapterDic[adKey];
					// retData[adKey] = "-数据值为空-";
				}
			} else if (Array.isArray(adapterDic[adKey])) {
				retData[adKey] = JSON.parse(JSON.stringify(adapterDic[adKey]));
				adapterDic[adKey].forEach((adKeyItem, index) => {
					if (sourceKeyList.indexOf(adKeyItem[adKeyItem.valueKey]) != -1 && !this
						.isEmpty(sourceData[adKeyItem[adKeyItem.valueKey]]).isEmpty) {
						this.setConsole("源数据对象值：", adKeyItem[adKeyItem.valueKey]);
						this.setConsole("注入对象值：", sourceData[adKeyItem[adKeyItem.valueKey]]);
						retData[adKey][index][adKeyItem.valueKey] = sourceData[adKeyItem[adKeyItem
							.valueKey]];
						this.setConsole("注入后对象：", retData[adKey][index]);
					} else {
						retData[adKey][index][adKeyItem.valueKey] = emptyHolder.length ?
							emptyHolder : adKeyItem[adKeyItem.valueKey];
						// retData[adKey][index][adKeyItem.valueKey] = "-数据值为空-";
					}
				})
			} else if (Object.prototype.toString.call(adapterDic[adKey]).indexOf("Object") != -1) {
				retData[adKey] = this.injectionObject(sourceData, adapterDic[adKey], emptyHolder);
			}
		});
		return retData;
	}

	/**
	 * @author QL
	 * @functionName formatDate
	 * @param { Date } date Date() 类型的日期值
	 * @param { String } format 格式化的格式字符规范
	 * @date 2021-12-24 13:49:21
	 * @version V..
	 * @description 根据format规则 格式化date时间戳
	 * @example
	 * this.dateTest = this.$ocnUtils.formatDate(new Date(), 'YYYY/MM/DD hh:mm:ss');
	 */
	formatDate(date, format = 'yyyy/MM/dd HH:mm:ss') {
		const map = {
			year: {
				value: date.getFullYear(),
				regExpAttributes: 'i'
			},
			month: {
				value: date.getMonth() + 1
			},
			date: {
				value: date.getDate(),
				regExpAttributes: 'i'
			},
			hour: {
				value: date.getHours(),
				regExpAttributes: 'i'
			},
			minute: {
				value: date.getMinutes()
			},
			second: {
				value: date.getSeconds()
			},
			quarter: {
				value: Math.floor((date.getMonth() + 3) / 3),
				regExpAttributes: 'i'
			},
			millisecond: {
				value: date.getMilliseconds()
			}
		}

		for (const key in map) {
			format = this.formatType(key, format, map[key].value, map[key].regExpAttributes)
		}

		return format
	}
	formatType(type, format, value, regExpAttributes) {
		const regExpMap = {
			year: '(Y+)',
			month: '(M+)',
			date: '(D+)',
			hour: '(h+)',
			minute: '(m+)',
			second: '(s+)',
			quarter: '(q+)',
			millisecond: '(S)'
		}

		if (new RegExp(regExpMap[type], regExpAttributes).test(format)) {
			const replaceStr = type === 'year' ?
				value.toString().substr(4 - RegExp.$1.length) :
				(RegExp.$1.length === 1) ? value : this.pad(value)
			format = format.replace(RegExp.$1, replaceStr)
		}

		return format
	}
	pad(value) {
		return ('00' + value).substr(('' + value).length)
	}

	/**
	 * @author QL
	 * @functionName computTimeHorizon
	 * @param { Date } whereTheTime 是一个未格式化/已格式化的日期时间数据
	 * @param { Number } type
	 * @date 2021-12-24 16:17:44
	 * @version V..
	 * @description
	 * 根据type 选择的计算需求，计算whereTheTime的相应计算值
	 * type {1,2,3,4,5,6,7}
	 * 1-所在周的起止日期
	 * 2-所在月的起止日期
	 * 3-所在季度的起止日期
	 * 4-所在半年的起止日期
	 * 5-所在全年的起止日期
	 * 6-所在月度前一个月的起止日期
	 * @example
	 * this.dateTest = this.$***.computTimeHorizon(new Date(),2);
	 * this.dateTest = this.$***.computTimeHorizon(new Date(this.dateTest[0]), 6);
	 * this.setConsole('获取今天所在月度上个月度的起止日期：',this.dateTest);
	 * this.dateTest = this.$***.computTimeHorizon(new Date(),3);
	 * this.dateTest = this.$***.computTimeHorizon(new Date(this.dateTest[0]), 6);
	 * this.dateTest = this.$***.computTimeHorizon(new Date(this.dateTest[0]),3);
	 * this.setConsole('获取今天所在季度上个季度的起止日期：',this.dateTest);
	 */
	computTimeHorizon(whereTheTime, type) {
		var d = new Date(whereTheTime);
		var year = d.getFullYear();
		var month = parseInt(d.getMonth()) + 1;
		switch (type) {
			case 1: //周
				//获取周一
				var beginWhereTheTime = this.GetMondayAndSunday(d);
				var dd = new Date(beginWhereTheTime);
				//获取周天
				dd.setDate(dd.getDate() + 6);
				var monthSunday = parseInt(dd.getMonth()) + 1;
				var endWhereTheTime =
					dd.getFullYear() +
					'/' +
					this.formatVal(monthSunday) +
					'/' +
					this.formatVal(dd.getDate());
				return [beginWhereTheTime, endWhereTheTime];
			case 2: //月
				//获取月第一天
				var fristDay = new Date(year, month, 1);
				var beginWhereTheTime =
					year +
					'/' +
					this.formatVal(month) +
					'/' +
					this.formatVal(fristDay.getDate());
				//获取月最后一天
				var lastDay = new Date(year, month, 0);
				var endWhereTheTime =
					year +
					'/' +
					this.formatVal(month) +
					'/' +
					this.formatVal(lastDay.getDate());
				return [beginWhereTheTime, endWhereTheTime];
			// break;
			case 3: //季度
				//获取当前月所在季度
				var quarter = this.getQuarterStartMonth(month);
				if (quarter != 0) {
					//获取季度第一天
					var fristDay = new Date(year, quarter, 1);
					//获取季度最后一天
					var lastDay = new Date(year, quarter + 2, 0);
					var beginWhereTheTime =
						year +
						'/' +
						this.formatVal(quarter) +
						'/' +
						this.formatVal(fristDay.getDate());
					var endWhereTheTime =
						year +
						'/' +
						this.formatVal(quarter + 2) +
						'/' +
						this.formatVal(lastDay.getDate());
					return [beginWhereTheTime, endWhereTheTime];
				}
				break;
			case 4: //半年
				var startMonth = 0;
				var endMonth = 0;
				if (month < 7) {
					//上半年
					startMonth = 1;
					endMonth = 6;
				} else {
					//下半年
					startMonth = 7;
					endMonth = 12;
				}
				//获取第一天
				var fristDay = new Date(year, 1, 1);
				//获取最后一天
				var lastDay = new Date(year, 6, 0);
				var beginWhereTheTime =
					year +
					'/' +
					this.formatVal(startMonth) +
					'/' +
					this.formatVal(fristDay.getDate());
				var endWhereTheTime =
					year +
					'/' +
					this.formatVal(endMonth) +
					'/' +
					this.formatVal(lastDay.getDate());
				return [beginWhereTheTime, endWhereTheTime];
			case 5: //全年
				var beginWhereTheTime = year + '/01/01';
				var endWhereTheTime = year + '/12/31';
				return [beginWhereTheTime, endWhereTheTime];
			case 6: // 前一个月
				month = month - 1;
				if (month <= 0) {
					month = 12 - month;
					year = year - 1;
				}
				//获取月第一天
				var fristDay = new Date(year, month, 1);
				var beginWhereTheTime =
					year +
					'/' +
					this.formatVal(month) +
					'/' +
					this.formatVal(fristDay.getDate());
				//获取月最后一天
				var lastDay = new Date(year, month, 0);
				var endWhereTheTime =
					year +
					'/' +
					this.formatVal(month) +
					'/' +
					this.formatVal(lastDay.getDate());
				return [beginWhereTheTime, endWhereTheTime];
		}
	}
	GetMondayAndSunday(dd) {
		var week = dd.getDay(); //获取时间的星期数
		var minus = week ? week - 1 : 6;
		dd.setDate(dd.getDate() - minus); //获取minus天前的日期
		var y = dd.getFullYear();
		var m = dd.getMonth() + 1; //获取月份
		var d = dd.getDate();
		return y + '/' + this.formatVal(m) + '/' + this.formatVal(d);
	}
	getQuarterStartMonth(month) {
		var quarterStartMonth = 0;
		if (month < 4) {
			quarterStartMonth = 1;
		}
		if (3 < month && month < 7) {
			quarterStartMonth = 4;
		}
		if (6 < month && month < 10) {
			quarterStartMonth = 7;
		}
		if (month > 9) {
			quarterStartMonth = 10;
		}
		return quarterStartMonth;
	}
	formatVal(value) {
		if (value < 10) {
			value = '0' + value;
		}
		return value;
	}

	/**
	 * @author QL
	 * @functionName getDayDiff
	 * @param { Date } date1 未格式化的日期时间类型
	 * @param { Date } date2 未格式化的日期时间类型 
	 * @date 2021-12-24 16:19:36
	 * @version V..
	 * @description 计算两个日期之间的日差值
	 * @example
	 * this.dateTest = this.$tools_getDayDiff(new Date(), new Date('2021-04-16'));
	 * this.setConsole('计算当前日期与2021-04-16的日期差：',this.dateTest);
	 */
	getDayDiff(date1, date2) {
		return Math.abs(Math.floor((this.getZeroStamp(date1) - this.getZeroStamp(date2)) / DAY_TIMESTAMP))
	}
	getZeroStamp(date) {
		const year = date.getFullYear()
		const month = date.getMonth() + 1
		const day = date.getDate()
		return +new Date(year + '/' + month + '/' + day + ' 00:00:00')
	}

	/**
	 * @author QL
	 * @functionName antiShakeRequest
	 * @param { Function } func 防止重复触发的方法
	 * @param { String } timer 自定义对应防抖方法的定时器id(名称)，隔离不同方法的计时器，独立处理各自的防抖定时器
	 * @param { Number } wait 判断防止重复触发的间隔时间
	 * @date 2021-12-29 10:31:38
	 * @version V..
	 * @description 函数防抖方法，用于解决部分方法不能频繁反复重复触发的情况
	 */
	antiShake(func, timer, wait) {
		let _this = this;
		if (Object.keys(this.antiShakeTimers).indexOf(timer) < 0 || this.antiShakeTimers[timer] == null) {
			this.antiShakeTimers[timer] = setTimeout(() => {
				func();
				_this.antiShakeTimers[timer] = null;
			}, wait);
		} else {
			this.setConsole("防抖计时器已存在:", this.antiShakeTimers[timer]);
			if (this.antiShakeTimers[timer] !== null) clearTimeout(this.antiShakeTimers[timer]);
			this.antiShakeTimers[timer] = setTimeout(() => {
				func();
				_this.antiShakeTimers[timer] = null;
			}, wait);
		}

	}
}

export default UtilMethods
